#include <iostream>
#include <vector>
#include <typeinfo>
using namespace std;
class Security
{
protected:
    enum
    {
        BASEID = 0
    };

public:
    virtual ~Security() {}
    virtual bool isA(int id)
    {
        return (id == BASEID);
    }
};

class Stock : public Security
{
    typedef Security Super;

protected:
    enum
    {
        OFFSET = 1,
        TYPEID = BASEID + OFFSET
    };

public:
    // 确认是不是当前自己的类型或父类类型
    bool isA(int id)
    {
        return id == TYPEID || Super::isA(id);
    }
    static Stock *dynacast(Security *s)
    {
        return (s->isA(TYPEID)) ? static_cast<Stock *>(s) : 0;
    }
};
class Bond : public Security
{
    typedef Security Super;

protected:
    enum
    {
        OFFSET = 2,
        TYPEID = BASEID + OFFSET
    };

public:
    bool isA(int id)
    {
        return id == TYPEID || Super::isA(id);
    }
    static Bond *dynacast(Security *s)
    {
        return (s->isA(TYPEID)) ? static_cast<Bond *>(s) : 0;
    }
};

class Investment : public Security
{
    typedef Security Super;

protected:
    enum
    {
        OFFSET = 3,
        TYPEID = BASEID + OFFSET
    };

public:
    bool isA(int id)
    {
        return id == TYPEID || Super::isA(id);
    }
    static Investment *dynacast(Security *s)
    {
        return (s->isA(TYPEID)) ? static_cast<Investment *>(s) : 0;
    }
    void special()
    {
        cout << "special" << endl;
    }
};

class Metal : public Investment
{
    typedef Investment Super;

protected:
    enum
    {
        OFFSET = 4,
        TYPEID = BASEID + OFFSET
    };

public:
    bool isA(int id)
    {
        return id == TYPEID || Super::isA(id);
    }
    static Metal *dynacast(Security *s)
    {
        return (s->isA(TYPEID)) ? static_cast<Metal *>(s) : 0;
    }
};
template <int id>
class Announce
{
private:
    /* data */
public:
    Announce(/* args */);
    ~Announce();
};
template <int id>
Announce<id>::Announce(/* args */)
{
    cout<< typeid(*this).name()<<"constuctor"<<endl;
}

template <int id>
Announce<id>::~Announce()
{
    cout<< typeid(*this).name()<<"deconstuctor"<<endl;
}
class X :Announce<0>
{
private:
    Announce<1> m1;
    Announce<2> m2;
public:
    X(/* args */);
    ~X();
};

X::X(/* args */)
{
    cout << "X::x()"<<endl;
}

X::~X()
{
    cout << "X::~x()"<<endl;
}
int main()
{
    vector<Security *> portfolio;
    portfolio.push_back(new Metal);
    portfolio.push_back(new Investment);
    portfolio.push_back(new Bond);
    portfolio.push_back(new Stock);
    for (vector<Security *>::iterator it = portfolio.begin(); it != portfolio.end(); ++it)
    {
        Investment *cm = Investment::dynacast(*it);
        if (cm)
        {
            cm->special();
        }
        else
        {
            cout << "not an Investment" << endl;
        }
    }

    // 上诉操作可以用动态类型检查来实现
    for (vector<Security *>::iterator it = portfolio.begin(); it != portfolio.end(); ++it)
    {
        Investment *cm = dynamic_cast<Investment *>(*it);
        if (cm)
        {
            cm->special();
        }
        else
        {
            cout << "not an Investment" << endl;
        }
    }

    // 传引用则用trycatch实现
    Metal m;
    Security &s = m;
    try
    {
        Investment &c = dynamic_cast<Investment &>(s);
        cout << "It is  Investment" << endl;
    }
    catch (const std::exception &e)
    {
        cout << "error type" << endl;
    }

    try
    {
        Bond &b = dynamic_cast<Bond &>(s);
        cout << "It is   Bond" << endl;
    }
    catch (const std::exception &e)
    {
        cout << "error type" << endl;
    }

    //8.2 typeid操作符，获取对象运行时信息的另一个方法，就是用typeid操作符完成的
    cout << typeid(m).name()<<endl;
   
    //8.2.1类型转换到中间层次
    //dynamic_cast不仅能发现准确的类型，并且能在多层的继承层次结构中将类型转换到中间层类型

    //8.2.2 void*指针
    //它不能和void*型指针一起工作

    //void* v =new Metal;
    //error//Investment* s = dynamic_cast<Investment*>(v);
     
    //8.2.3 运用带模版的rtti
    X x;

    //8.3多重继承
    //多重继承只能用dynamic_cast ，不能用MI* MIp = （MI*）bbp

    //8.4合理使用rtti

    //8.5rtti的机制和开销
    //实现rtti典型的方法时，通过在类的虚函数表中放置一个附加指针。这个指针指向那个特别类型的type-info结构

    

    return 0;
}
